﻿using System.Collections.Generic;

namespace RIFF.Chunk
{
    /// <summary>
    /// RIFF Chunk、LIST Chunk 的基类，Data 字段是嵌套的子 Chunk。
    /// </summary>
    public class ListBase : Chunk
    {
        /// <summary>
        /// 类型
        /// </summary>
        protected FourCC listType;

        /// <summary>
        /// 子 Chunk 集合
        /// </summary>
        public List<Chunk> SubChunks { get; }

        /// <summary>
        /// 克隆一个 Chunk，将其 Data 解释为类型和子 Chunk 集合。
        /// </summary>
        /// <exception cref="ChunkException"/>
        /// <param name="chunk">克隆源</param>
        public ListBase(Chunk chunk) : base(chunk)
        {
            try
            {
                ReadSubChunks(out FourCC type, out List<Chunk> chunks);
                listType = type;
                SubChunks = chunks;
            }
            catch (System.Exception ex)
            {
                throw new ChunkException("解析 SubChunks 失败", ex);
            }
        }

        /// <summary>
        /// 将 Data 解释为类型和子 Chunk 集合
        /// </summary>
        /// <exception cref="ChunkSizeException"/>
        /// <param name="type">返回 Data 类型</param>
        /// <param name="data">返回子 Chunk 集合</param>
        protected void ReadSubChunks(out FourCC type, out List<Chunk> data)
        {
            var keepPosition = stream.Position;
            stream.Position = dataPosition;
            var maxPosition = dataPosition + Size;

            var buf = new byte[4];
            stream.Read(buf);
            type = new FourCC(buf);

            data = new List<Chunk>();
            while (stream.Position < maxPosition)
            {
                var c = new Chunk(stream);
                var d = c.Id.ToString() switch
                {
                    "RIFF" => throw new IllegalChunkException("子 Chunk 中出现非法 RIFF Chunk，仅顶级允许出现"),
                    "LIST" => c.ToListChunk(),
                    "fmt " => c.ToFormatChunk(),
                    "fact" => c.ToFactChunk(),
                    "data" => c.ToDataChunk(),
                    _ => c,
                };
                data.Add(d);
            }

            if (stream.Position > maxPosition)
            {
                throw new ChunkSizeException();
            }

            stream.Position = keepPosition;
        }
    }
}
